<template>
  <div style="position: relative"
       :class="'lang-' + $props.gitInfo.language.toLowerCase() + ' env-' + currentSystemEnv">
    <el-row :gutter="12" type="flex" ref="jenkins">
      <el-col :span="12">
        <el-card shadow="always" class="bg-logo">
          <div class="bg-logo-c"></div>

          <template #header>
            <div style="text-align: center">
              Git信息
            </div>
          </template>
          <kv label="git地址">
            <div v-if="$props.gitInfo.id" class="wrap">
              {{ $props.gitInfo.server.url + $props.gitInfo.path }}
            </div>
          </kv>
          <kv label="开发语言">
            <el-tag v-if="$props.gitInfo.id">
              {{ $props.gitInfo.language }}
            </el-tag>
            :
            <el-tag v-if="$props.gitInfo.id">{{ $props.gitInfo.languageVersion }}</el-tag>
          </kv>
          <kv>
            <template #k>
              <div class="k">
                <selector style="width:125px;min-width:125px;" v-model="$data.git_range"
                          :data="{'last15day':'近两周分支', 'last8':'最近8分支','all':'全部分支'}"
                          :enumCount="1"></selector>
              </div>
            </template>
            <selector style="min-width:80%" mode="radio" v-model="$data.query.gitBranch" chk="*"
                      v-if="$data.query.gitId" :key="$data.git_range"
                      fields="name,fullName"
                      :data="auto_branches"
                      @change="branch_change"></selector>
          </kv>
          <kv label="git路径">

            <el-tag effect="dark" v-if="$props.gitInfo?.folders?.length == 1 && $props.gitInfo.folders[0]?.path=='.'"
                    style="margin-left:12px;">项目根目录!
            </el-tag>
            <selector v-else v-model="$data.query.name"
                      :data="$props.gitInfo.folders" @change="path_change"
                      fields="name,path" style="width:80%;"
                      chk="*"></selector>

          </kv>

          <kv label="Git版本" v-if="$data.nexusComInfo.defVersion">
            <div>{{ $data.nexusComInfo.defVersion }}</div>
          </kv>

          <kv label="git提交信息">
            <div v-if="git_branch_info && git_branch_info.commitId">
              <div>提交于:
                <el-tag>{{ diff_date(git_branch_info.commitAt) }}</el-tag>
                {{ git_branch_info.commitAt_res }}
              </div>
              <div>提交Id: {{ git_branch_info.commitId.slice(0, 12) }}...{{
                  git_branch_info.commitId.slice(-12)
                }}
              </div>
              <el-tag>{{ git_branch_info.commitMessage.slice(0, 64) }}</el-tag>
            </div>
            <div v-else>
              没有分支信息
            </div>
          </kv>
        </el-card>
      </el-col>
      <el-col :span="12">
        <el-card shadow="always" v-if="$props.gitInfo.isLib">

          <template #header>
            <div style="text-align: center">
              库信息
            </div>
          </template>
          <kv label="当前配置">
            <el-tag effect="dark">{{ currentSetting.name }}</el-tag>
          </kv>
          <kv label="私服地址">
            <div>{{ currentSetting.nexusServer.hostUrl }}</div>
          </kv>

          <template>
            <kv label="组件名">
              <div>{{
                  $data.nexusComInfo.packageName || ($data.nexusComInfo.groupId + ":" + $data.nexusComInfo.artifactId)
                }}
              </div>
            </kv>
          </template>
          <kv label="描述">
            <div v-if="$data.nexusComInfo.description">{{ $data.nexusComInfo.description.slice(0, 120) }}</div>
          </kv>

          <template v-if="$data.nexusComInfo.nexusVersion">
            <kv label="仓库版本">

              <el-tag> {{
                  $data.nexusComInfo.nexusVersion
                }}
              </el-tag>

              <template v-if="$data.nexusComInfo.nexusVersion != $data.nexusComInfo.defVersion">
                <span style="margin:0 5px;">⤴</span>
                <el-tag type="warning">
                  {{ $data.nexusComInfo.defVersion }}
                </el-tag>
              </template>
            </kv>
            <kv label="maven定义">
              <pre>{{ mvnDefine }}</pre>
            </kv>

            <kv label="更新时间">
              <div>{{ $data.nexusComInfo.lastModified }}</div>
              <el-tag style="margin-left: 4px;">{{ diff_date($data.nexusComInfo.lastModified) }}</el-tag>
            </kv>
          </template>
          <div v-else>未部署!</div>

        </el-card>
        <el-card shadow="always" v-else>

          <template #header>
            <div style="text-align: center">
              部署信息
            </div>
          </template>

          <kv label="当前配置">
            <el-tag effect="dark" style="cursor:default" @dblclick="view_setting">{{ currentSetting.name }}</el-tag>
          </kv>

          <kv label="环境">
            <el-tag>{{ currentSetting.profile }}</el-tag>
            <el-tag>{{ currentSetting.clusterDeployEnv }}</el-tag>
          </kv>
          <kv label="集群">
            <el-tag type="danger" effect="dark" style="cursor: default"
                    @dblclick="view_cluster($data.query.clusterCode)">{{ $data.query.clusterCode }}
            </el-tag>

            <div style="margin-left:8px;color:dimgray">表示: k8s-ns <span
                v-if="$props.gitInfo.language == 'Java' || $props.gitInfo.language == 'Node'">,nacos-ns</span></div>

          </kv>

          <kv label="流水线">
            <el-tag> {{ currentSetting.pipelineTemplate }}</el-tag>
          </kv>

          <kv label="虚拟目录" v-if="jv.ops?.versions?.nginxVpathStyle?.includes($props.gitInfo.language)">
            <el-tag>{{ app_folder.location }}</el-tag>
            <el-tag>{{ app_folder.cnname || app_folder.name }}</el-tag>
          </kv>
          <kv label="应用名" v-else>
            <el-tag>{{ app_folder.name }}</el-tag>
            <el-tag v-if="app_folder.cnname && app_folder.cnname != app_folder.name">{{ app_folder.cnname }}</el-tag>
          </kv>

          <kv label="k8s服务" v-if="currentSetting.pipelineTemplate.basicSame('K8s')">
            <el-tag> {{ get_job_name(app_folder.name) }}</el-tag>
            :
            <el-tag v-if="$data.current_image?.imageVersion">
              {{ $data.current_image.imageVersion }}
            </el-tag>
          </kv>


        </el-card>
      </el-col>
    </el-row>
    <template v-if="$data.query.gitBranch && $data.query.name">
      <div style="display: block;margin: 20px auto;text-align: center">
        <el-button type="primary" class="flow" v-if="$props.gitInfo.isLib || $data.lockResult.canDeploy"
                   @click="gen_click()" :icon="Tools">部署
        </el-button>
        <el-tag v-else type="danger">{{ $data.lockResult.lockInfo }}</el-tag>

        <el-button style="margin-left:24px;" @click="log_click()">日志</el-button>
        <el-button style="margin-left:24px;" @click="jenkins_click()">打开Jenkins</el-button>


        <template v-if="!$props.gitInfo.isLib">
          <el-button style="margin-left:24px;" @click="lock_click()"
                     v-if="$data.query.name && $data.lockResult.canDeploy">{{ app_folder.name }} 锁定
            {{ $data.query.gitBranch }}
          </el-button>
          <el-button style="margin-left:24px;" @click="unlock_click()"
                     v-if="$data.query.name && $data.lockResult.canUnlock">解锁
          </el-button>
          <el-tag v-if="$data.lockResult.canDeploy && $data.lockResult.lockInfo">{{
              $data.lockResult.lockInfo
            }}
          </el-tag>
        </template>

      </div>
      <div v-if="$data.logs.pendding">队列中...</div>
      <div style="position: relative">
        <el-steps :active="$data.logs.step" v-if="$data.logs?.steps?.length" finish-status="success"
                  process-status="wait"
                  style="margin: 20px;" :key="$data.logs.version">
          <el-step :title="item.title" v-for="(item,index) in $data.logs.steps" :key="index"
                   @click.native="pop_msg(item)"
                   :status="item.status"
          >
          </el-step>
        </el-steps>
        <clock v-if="$data.working" style="position: absolute;right:0;"></clock>
      </div>
    </template>

    <el-dialog :title="$data.log.title" v-model="$data.log_visible" width="80vw" height="80vh">
      <pre v-html="$data.log.content" style="overflow: auto;"/>
    </el-dialog>
  </div>
</template>

<script type="text/ecmascript-6" setup>
// import deployRef from "../../dev/jenkins-log/jenkins-log-ref";

import {Tools} from '@element-plus/icons-vue'

defineOptions({
  name: "jenkins-com",
  inheritAttrs: true,
});

//定义 vue2的this,当前组件
const $self = getCurrentInstance();

//定义 $attrs
const $attrs = useAttrs();

var topJson = jv.query2Json(top.location.href);
//定义data
const $data = reactive({
  working: false,
  git_range: "last15day",
  branches: [],
  current_image: {},

  query: {
    gitId: topJson["gitId"] || "",
    gitBranch: topJson.gitBranch || "",
    name: topJson["name"] || "",
    clusterName: "",
    targetEnv: ""
  },
  nexusComInfo: {},
  timer_id: 0,
  log_visible: false,
  logs: {steps: [], result: "", version: 0},
  log: {},

  lockResult: {
    canDeploy: true,
    canUnlock: false,
    lockInfo: ""
  }
});

var net_err_times = 0;
var next_log_all_stage = true;

const $props = defineProps({
  gitInfo: {type: Object}
});

const mvnDefine = $computed(() => {
  if (!$data.nexusComInfo || !$data.nexusComInfo.defVersion) {
    return "";
  }

  return `<dependency>
  <groupId>${$data.nexusComInfo.groupId}</groupId>
  <artifactId>${$data.nexusComInfo.artifactId}</artifactId>
  <version>${$data.nexusComInfo.defVersion}</version>
</dependency>`
})


//定义事件
const $emit = defineEmits(["update:modelValue", "loaded"]);

const currentSetting = $computed(function () {
  return top.jv.currentSetting;
});

const view_setting = e => {
  jv.$router.push(`/dev/app-deploy-setting/view/${jv.currentSetting.id}`);
}

const view_cluster = clusterCode => {
  jv.$route.push(`/dev/cluster-info/edit/${clusterCode}`);
}

const currentSystemEnv = $computed(function () {
  var profile = top.jv.currentSetting.profile;
  if (!profile) {
    return "dev"
  }
  if (profile.includes("main") || profile.includes("prod")) {
    return "prod"
  }

  if (profile.includes("test")) {
    return "test"
  }
  return "dev";
})

const diff_date = $computed(() => {
  return function (dt) {
    if (!dt) return "";

    var now = Date.now()
    //linux 系统不显示时区
    if ((Intl.DateTimeFormat().resolvedOptions().timeZone || "").includes("Unknown")) {
      now += 8 * 3600 * 1000;
    }

    var diff_ms = now - Date.from(dt).valueOf()
    return jv.getTimeDiffSummary(diff_ms, {">": "{msg} 前", "<": "未来 {msg} 后", "==": "刚刚"});
  };
})


const auto_branches = $computed(function () {
  if ($data.git_range == "last15day") {
    var now = Date.now();
    return $data.branches.filter(it => {
      return (now - Date.from(it.commitAt)) / 3600_000 / 24 <= 15;
    })
  } else if ($data.git_range == "last8") {
    return $data.branches.slice(0, 8)
  }
  return $data.branches
});
const app_folder = $computed(function () {
  return $props.gitInfo.folders.find(it => it.name == $data.query.name) || {}
});
const git_branch_info = $computed(function () {
  var ret = $data.branches.find(it =>
      it.name.split(",").intersect($data.query.gitBranch.split(",")).filter(it2 => it2).length
  ) || {};
  if (ret.commitAt) {
    ret.commitAt_res = ret.commitAt.toDateString()
  }
  return ret;
});

const get_job_name = function (serviceName) {
  if (!serviceName) {
    return "";
  }

  var productLineCode = $props.gitInfo.productLine.code;
  var lang = $props.gitInfo.language.toLowerCase();

  var setting = currentSetting;
  var serviceNameMode = setting.serviceNameStyle;

  if (serviceNameMode == "Default") {
    return serviceName
  }

  if (serviceNameMode == "ProductLineCode") {

    var sects = serviceName.getKebabCase().split("-");
    if (sects[0] != productLineCode) {
      sects.insertAt(0, productLineCode);
    }

    return sects.filter(it => it != "-").join("-");
  }


  if (serviceNameMode == "Language") {
    var sects = serviceName.getKebabCase().split("-");
    if (sects.getLast() != lang) {
      sects.push(lang);
    }

    return sects.join("-");
  }

  if (serviceNameMode == "ProductLineCodeLanguage") {
    var sects = serviceName.getKebabCase().split("-");
    if (sects[0] != productLineCode) {
      sects.insertAt(0, productLineCode);
    }
    if (sects.getLast() != lang) {
      sects.push(lang);
    }

    return sects.filter(it => it != "-").join("-");
  }
};
const load_lock_status = function () {
  jv.$http.post("/ops/jenkins/lock-status", $data.query)
      .then(res => {
        $data.lockResult = res.data.data;
      });
}


const changeToUrl = function () {
  jv.saveToHistoryUrlQuery(top, $data.query)
  jv.$saveData("location", location.search)
};
const path_change = function (v, m, p) {
  if (!$data.query.gitId || !$data.query.name) {
    $data.current_image = {};
    return;
  }

  $data.query.name = m.name;
  changeToUrl();
  setCurrentVersion()


  load_lock_status();
};

const jenkins = ref();

const setCurrentVersion = function () {
  if (!$data.query.name) {
    return;
  }
  if ($props.gitInfo.isLib) {
    if (!jenkins.value || jenkins.value.$el.chk({$data: $data}) == false) {
      return;
    }
    var postQuery = Object.assign(
        {},
        $data.query,
        {targetEnv: jv.targetEnv}
    )
    jv.$http.post('/dev/nexus/component/info', postQuery).then(res => {
      $data.nexusComInfo = res.data.data
    });
    return;
  }

  var setting = currentSetting;
  if (setting.pipelineTemplate != "K8s") {
    return;
  }
  var name = get_job_name($data.query.name)
  var p = {};
  p.names = [name]
  p.take = 99;
  p.namespace = $props.gitInfo.clusterCode;
  p.productLineCode = $props.gitInfo.productLine.code;
  p.language = $props.gitInfo.language;
  p.targetEnv = jv.targetEnv;
  jv.$http.post('/ops/k8s/deployment/list', p).then(res => {
    const list = res.data.data;
    list.forEach(it => {
      var sect = it.imageNameVersion.split(":")
      if (sect.length > 1) {
        it.imageVersion = sect.getLast();
      }
    })
    $data.current_image = list.find(it => it.name == name) || {}
  })
};
const branch_change = function (v, m) {
  changeToUrl();
  setCurrentVersion()
};
const gen_click = function (ev) {
  if (jenkins.value.$el.chk({$data: $data}) == false) {
    return;
  }
  $data.logs.pendding = true;
  var postQuery = Object.assign(
      {},
      $data.query,
      {targetEnv: jv.targetEnv}
  )

  jv.$http.post("/ops/jenkins/deploy-job", postQuery)
      .then(res => {
        jv.info(`已执行 ${$data.query.name}:${$data.query.gitBranch} !`)
        log_click();
      })
};
const pop_msg = function (item) {
  $data.log = item;
  $data.log_visible = true;
};
const log_click = function () {
  net_err_times = 0;
  next_log_all_stage = true;
  get_log({
    gitId: $data.query.gitId,
    git_branch: git_branch_info.name
  });
};

const lock_click = function () {

  jv.$http.post("/ops/jenkins/lock-deploy", $data.query)
      .then(res => {
        jv.info(`成功锁定 ${$data.query.gitBranch} !`)
        load_lock_status();
      })
}


const unlock_click = function () {

  jv.$http.post("/ops/jenkins/unlock-deploy", $data.query)
      .then(res => {
        jv.info(`成功解锁 ${$data.query.gitBranch} !`)
        load_lock_status();
      })
}


watch(() => $props.gitInfo, v => {
  if (v?.folders?.length == 1) {
    load_lock_status();
  }
}, {immediate: true})


const jenkins_click = function () {
  var setting = currentSetting;

  window.open(jv.getFullUrl(setting.jenkinsServer.hostUrl) + "/job/" + get_job_name(app_folder.name), "jenkins")
};


const get_log = async function (option) {
  if (!$self.vnode.el.isConnected) {
    return;
  }

  if ($data.timer_id) {
    clearTimeout($data.timer_id);
  }
  if (!option.gitId) {
    return;
  }
  if (!$data.query.name) {
    return;
  }
  if (!option.git_branch) {
    return;
  }
  if ($data.log_loading) {
    return;
  }

  if (document.hidden) {
    $data.timer_id = await jv.sleep(1_000);
    return await get_log(option);
  }

  if ($data.timer_id) {
    clearTimeout($data.timer_id);
  }
  $data.timer_id = await jv.sleep(3000);

  var getRow = function (row) {
    var status = "wait";
    if (row.successful === true) {
      status = "success"
    } else if (row.successful === false) {
      status = "error"
    }
    return {title: row.name, content: row.content, status: status}
  }
  var p = {};
  p.gitId = option.gitId;
  p.branch = option.git_branch
  p.appName = $data.query.name
  if (!next_log_all_stage && $data.logs.steps.length && $data.logs.steps.getLast().status == "wait") {
    p.lastStage = true;
  }


  $data.working = true;

  var e = null;
  $data.log_loading = true;

  var res = await jv.$http.post("/ops/jenkins/last-log", p).catch(ex => {
    net_err_times++;
    if (ex.code == 'ERR_NETWORK') {
      return {data: {}}
    } else {
      e = ex;
    }
  });
  $data.log_loading = false;
  if (e) {
    $data.log_loading = false;
    $data.timer_id = await jv.sleep(3000);
    if (e instanceof Error) {
      jv.error(e.message);
      $data.timer_id = await jv.sleep(3000);
    }
    return await get_log(option);
  }


  if (!res.data.data) {
    if (net_err_times > 30) {
      $data.working = false
      return;
    }

    await jv.sleep(3000);
    return await get_log(option);
  }


  net_err_times = 0;
  if (res.data.data && res.data.data.length) {
    $data.logs.pendding = false;
  }
  if (next_log_all_stage) {
    next_log_all_stage = false;
  }
  var rows = res.data.data.map(it => getRow(it))
  if (p.lastStage) {
    var lastStep_new = rows.getLast();
    if (lastStep_new) {
      var index = $data.logs.steps.IndexOf(it => it.title == lastStep_new.title);
      if (index < 0) {
        next_log_all_stage = true;
        $data.logs.steps.forEach(it => {
          it.status = "success"
        });
        $data.logs.steps.push(lastStep_new);
      } else {
        $data.logs.steps.splice(index, 1, lastStep_new);
      }
    } else {
      next_log_all_stage = true;
    }
  } else {
    $data.logs.steps = rows;
    $data.logs.result = res.data.value;
    $data.logs.step = $data.logs.steps.length;
    if (res.data.value === true) {
      $data.working = false

      jv.notify(`部署 ${$data.query.name}:${$data.query.gitBranch} 成功完成！`)
      return
    } else if (res.data.value === false) {
      $data.working = false
      jv.notify(`部署 ${$data.query.name}:${$data.query.gitBranch} 失败！`)
      return
    }
  }

  $data.logs.version++;

  await get_log(option);
};


onMounted(function () {

  var gitId = topJson["gitId"]
  if (gitId) {
    $data.query.gitId = gitId;
  }
  var name = topJson["name"]
  if (name) {
    $data.query.name = name;
  }

  $data.query.gitBranch = topJson.gitBranch || "";
  $data.timer_id = 0;
  jv.$http.post('/dev/git/branch/list?gitId=' + $data.query.gitId).then(res => {
    $data.branches = res.data.data || [];
    $data.branches.forEach(it => {
      it.fullName = (it.committerName + " ⤴ " + it.name);
    });
//如果最近15天没有数据，自动切换到最近8分支
    if ($data.git_range == "last15day") {
      var now = Date.now();
      var last15Data = $data.branches.filter(it => {
        return (now - Date.from(it.commitAt)) / 3600_000 / 24 <= 15;
      })
      if (!last15Data.length) {
        $data.git_range = "last8"
      }
    }
  });


})

watch(() => $props.gitInfo, function (v) {
  $data.query.gitId = v.id;
  $data.query.clusterCode = v.clusterCode;
  v.folders
      .groupBy(it => {
        return it.path
      })
      .forEach(it => {
        if (it.data.length > 1) {
          it.data.forEach(it => {
            it.path += " (" + (it.cnname || it.name) + ")"
          })
        }
      });
  if (v.folders.length == 1) {
    $data.query.name = v.folders[0].name;
    setCurrentVersion();
  }
}, {immediate: true, deep: true});

</script>

<style lang="scss">
.bg-logo {
  position: relative;
  overflow: visible;


  .bg-logo-c {
    position: absolute;
    box-shadow: 0 0 6px -2px #888888;
    border-radius: 10px;
    top: 0;
    right: -82px;
    width: 152px;
    height: 70px;
    background-color: whitesmoke;

    &:after {
      content: "";
      position: absolute;
      width: 100%;
      height: 100%;
      z-index: 999;
      background-color: transparent;
    }

    &:hover::after {
      font-size: 18px;
      position: absolute;
      background-color: whitesmoke;
      z-index: 9999;
      display: flex;
      align-items: center;
      justify-content: space-evenly;
      border-radius: 20px;
      font-weight: bold;
      color: blue;
    }
  }

  &:before, &:after {
    content: "";
    width: 60px;
    height: 60px;
    position: absolute;
    top: 5px;
    z-index: 999;
    display: block;
    background-size: contain;
    background-clip: content-box;
    background-repeat: no-repeat;
  }

  &:before {
    right: 0;
  }

  &:after {
    right: -72px;
  }
}


.lang-vue {
  .k {
    color: #e54d26
  }

  .flow {
    color: white !important;
    background-color: #e54d26 !important;
    border-color: #e54d26 !important;
  }

  .bg-logo:before {
    background-image: url("../../../assets/ops/html5.png");
  }
}

.lang-java {
  .k {
    color: #1e4a90
  }

  .flow {
    color: white !important;
    background-color: #1e4a90 !important;
    border-color: #1e4a90 !important;
  }

  .bg-logo:before {
    background-image: url("../../../assets/ops/java.png");
  }
}

.lang-nuxt {
  .k {
    color: green;
  }

  .flow {
    color: white !important;
    background-color: green !important;
    border-color: green !important;
  }

  .bg-logo:before {
    background-image: url("../../../assets/ops/nuxt.png");
  }
}

.lang-node {

  .k {
    color: #04a2b8;
  }

  .flow {
    color: white !important;
    background-color: #04a2b8 !important;
    border-color: #04a2b8 !important;
  }

  .bg-logo:before {
    background-image: url("../../../assets/ops/nodejs.png");
  }
}


.env-dev {

  .bg-logo-c {
    &:hover::after {
      content: "开 发";
    }
  }

  .bg-logo:after {
    background-image: url("../../../assets/ops/dev.png");
  }
}

.env-test {
  .bg-logo-c {
    &:hover::after {
      content: "测 试";
    }
  }

  .bg-logo:after {
    background-image: url("../../../assets/ops/test.png");
  }
}

.env-prod, .env-main {
  .bg-logo-c {
    &:hover::after {
      content: "生 产";
    }
  }

  .bg-logo:after {
    background-image: url("../../../assets/ops/prod.png");
  }
}


</style>
